#ifndef _ARCHIVO_DATOS_H_
#define _ARCHIVO_DATOS_H_

/********************************************************************
 * ArchivoDatos.h
 * 
 * Descripcion: Esta clase representa una interfaz para los archivos de
 * datos de registros variables. El archivo esta organizado en bloques.
 * 
*********************************************************************/

#include "archivo.h"
#include "paresDatos.h"
#include "buffer.h"
#include "indice.h"
#include "indice_sec.h"

class ArchivoDatos : public Archivo {

	protected:
		Indice * indice_primario;
		IndiceSec * indice_secundario; //Referencia al archivo de indice secundario

	public:

		/*
		 * Constructor: Inicializa la clase archivo de datos con los datos necesarios.
		 * Inicialmente el archivo esta cerrado y el fd vale -1.
		 * Recibe el nombre, el tamaño del
		 * bloque utilizado para almacenar fisicamente los datos y el 
		 * tamano del bloque del archivo de indice primario.
		 */ 
		ArchivoDatos(std::string& nombre, unsigned int tam_bloque,unsigned int tam_bloque_indice = 0);
		
		/*
		 * Destructor de la clase. Si el archivo esta abierto, lo cierra.
		 */ 
		virtual ~ArchivoDatos(){}
				
		/*
		 * Crea el archivo fisicamente junto con todos los de control
		 * necesarios y carga el registro base.
		 */
		virtual void crear(std::string formato) throw(ExcepCreandoArch, ExcepSintaxisParser, ExcepBloqueTam) = 0; 
		
		/*
		 * Guarda en el archivo un registro. Debe chequear que sea del 
		 * tipo base.
		 * Si el archivo esta cerrado, o ya hay un registro con la misma clave unica
		 * que el que se va a ingresar en el archivo, arroja una excep.
		 * Tambien lo hace si el dato a ingresar, ocupa mas que el tamano
		 * del bloque del archivo.
		 */ 
		virtual void ingresar(TipoStruct * reg) throw(ExcepArchCerrado,ExcepRegExistente, ExcepBloqueTam) = 0;
		
		/*
		 * Quita los registros del archivo que tengan el valor
		 * pasado por parametro en el campo cuya posicion en el reg
		 * es pos_campo.
		 * Si el archivo esta cerrado, arroja una excep.
		 */
		virtual void quitar(std::vector<ParesDatos*> &elementos, std::vector<TipoStruct*> &resultado) throw(ExcepArchCerrado) = 0;
		
		/*
		 * Consulta los registros del archivo que tienen los valores ingresados
		 * en el vector de consultas.
		 * Si el archivo esta cerrado, arroja una excep.
		 * En caso de ejecutada la consulta devuelve en el vector resultado los
		 * registros consultados, los mismos deben ser liberados externamente.
		 */
		virtual void consultar(std::vector<ParesDatos*> &consultas, std::vector<TipoStruct*> &resultado)
									 throw(ExcepArchCerrado,ExcepLeerBloque)= 0;
 		
		/*
		 * Actualiza un registro en el archivo. Debe chequear que sea del 
		 * tipo base.
		 * Si el archivo esta cerrado o el registro a modificar no existe en el archivo,
		 * arroja una excep.
		 */ 
 		virtual void actualizar(TipoStruct * reg) throw(ExcepArchCerrado,ExcepRegInexistente,ExcepBloqueTam) = 0;
 		 
 		 /*
 		  * Devuelve el espacio libre en bytes
 		  */ 
 		 virtual unsigned int get_espacio_libre()  throw(ExcepArchCerrado, ExcepLeerBloque) = 0;
 		 
 		 /*
 		  * Devuelve la cantidad de registros del archivo de datos
 		  */ 										
 		 virtual unsigned int get_cant_regs() throw(ExcepArchCerrado);
 		 
 		 /*
 		  * Devuelve el espacio libre en bytes del indice primario.
 		  */ 
 		 virtual unsigned int get_esp_libre_indice()  throw(ExcepArchCerrado, ExcepLeerBloque) = 0;
 		 
 		 /*
 		  * Devuelve la cantidad de registros del indice primario.
 		  */ 										
 		 virtual unsigned int get_cant_regs_indice() throw(ExcepArchCerrado) = 0;
 		 
 		 /*
 		  * Devuelve el espacio libre en bytes del indice secundario.
 		  */ 
 		 virtual unsigned int get_esp_libre_ind_sec()  throw(ExcepArchCerrado, ExcepLeerBloque);
 		 
 		 /*
 		  * Devuelve la cantidad de registros del indice secundario.
 		  */ 										
 		 virtual unsigned int get_cant_regs_ind_sec() throw(ExcepArchCerrado);
 		 
 		/*
 		 * Devuelve el tamanio ocupado total por el indice primario, en bytes.
 		 */ 
 		 virtual long get_tam_arch_indice() throw(ExcepArchCerrado) = 0;
 		 
 		 /*
 		  * Devuelve el tamanio ocupado total por el indice secundario, en bytes.
 		  */
 		 virtual long get_tam_ind_sec() throw(ExcepArchCerrado);
 		 
 		  /*
 		  * Devuelve una referencia al indice del archivo. 
 		  */
 		 IndiceSec * get_indice();
 		 
 		 /*
 		  * Setea el indice secundario al archivo. 
 		  */
 		 void set_indice(IndiceSec * ind);
 		 
 		 		 
 	protected:
 		
 		/*
 		 * Quita recorriendo de forma secuencial todos los registros que cumplen
 		 * con los requisitos pedidos en el vector de elementos, y los devuelve
 		 * en el vector de resultados.
 		 */
 		void quitar_secuencial(std::vector<ParesDatos*> &elementos, std::vector<TipoStruct*> &resultado)
								 throw(ExcepLeerBloque);
		
		/*
		 * Quita todos los registros que cumplen con los requisitos pedidos en el
		 * vector de elementos, utilizando el indice secundario. Los devuelve en
		 * el vector de resultados. */
		bool quitar_indice_secundario(std::vector<ParesDatos*> &elementos, std::vector<TipoStruct*> &resultado)
									throw(ExcepLeerBloque);
		
		/*
		 * Realiza una consulta sobre todos los registros del archivo que cumplan con
		 * los requisitos pedidos en el vector de consultas. Para ello recorre secuencialmente
		 * el archivo. Guarda los resultados de la consulta en el vector de resultados.
		 */
		void consultar_secuencial(std::vector<ParesDatos*> &consultas, std::vector<TipoStruct*> &resultado)
									 throw(ExcepLeerBloque);
 		
 		/*
		 * Realiza una consulta sobre todos los registros del archivo que cumplan con
		 * los requisitos pedidos en el vector de consultas. Para ello utiliza el indice secundario
		 * el archivo. Guarda los resultados de la consulta en el vector de resultados.
		 */
 		bool consultar_indice_secundario(std::vector<ParesDatos*> &consultas, std::vector<TipoStruct*> &resultado)
									 throw(ExcepLeerBloque);
									 
		/*
		 * Dado un bloque, y la pos y tamanio de un reg, saca el reg del bloque y actualiza
		 * el archivo de espacios libres.
		 */
		virtual int sacar_reg_bloque(Bloque* bloque, TipoStruct * reg, unsigned int pos_reg, unsigned int tam_reg) =  0;
		
		/*
		 * Dados un bloque y un reg pasado por param, serializa el reg y lo pone en el bloque al final
		 * del mismo si este entra. De ser asi devuelve true.
		 * Si el reg no entra en el bloque devuelve false.
		 * actualiza el arch de esp libres
		 */
 		virtual bool poner_reg_en_bloque(Bloque* bloque, TipoStruct* reg) = 0;

			
		/*
		 * Dado un registro y un vector de consultas, devuelve true si el registro
		 * cumple con todas las consultas que se le efectuan.
		 */
		bool cumple_condiciones(TipoStruct &reg,std::vector<ParesDatos*>&consultas);
	
		/*
		 * Dado un vector de consultas y uno de registros, modifica el vector de registros
		 * dejando solo aquellos que cumplen con las exigencias de la consulta.
		 */
		void seleccionar_validos(std::vector<ParesDatos*> &consultas,std::vector<TipoStruct*> &resultado);
 
 		///// CONCATENA V2 AL FINAL DE V1. LO NECESITA LA CONSULTA.
		void concatenar(std::vector<TipoStruct*> &v1, std::vector<TipoStruct*> &v2);
		
		/*
		 * Devuelve la cantidad de bloques del archivo secuencial.
		 * La misma se guarda en el bloque 0 del archivo (bloque header).
		 */
		unsigned int get_cant_bloques_header();
		
		/*
		 * Dada una cantidad de bloques, lo guarda en el bloque 0 del archivo secuencial.
		 * Sirve para actualizar la cantidad de bloques del archivo cuando se agrega uno nuevo, etc.
		 */
		void set_cant_bloques_header(unsigned int cant);
		
		/*
		 * Devuelve la primera posicion donde se encuentran los registros
		 * en el archivo, es decir, luego de los tags de control
		 */ 
		virtual unsigned int get_primera_pos() = 0;
		
		/*
		 * Implementa la llamada al indice primario (si no es NULL) avisando
		 * la baja de un registro
		 */
		virtual void quitar_en_indice_primario(TipoStruct * reg);
		
		/*
		 * Cuenta la cantidad de registros que posee un bloque del archivo.
		 * Comienza desde la pos obtenida de get_primera_pos()
		 */ 
		virtual unsigned int get_cant_regs_bloque(Bloque* bloque);
};

#endif
